home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / pp / pp-6.0 / Chans / fax / fax_out.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-12-18  |  20.8 KB  |  930 lines

  1. /* fax_out.c: PP skelton for outbound fax channel */
  2.  
  3. # ifndef lint
  4. static char Rcsid[] = "@(#)$Header: /xtel/pp/pp-beta/Chans/fax/RCS/fax_out.c,v 6.0 1991/12/18 20:07:09 jpo Rel $";
  5. # endif
  6.  
  7. /*
  8.  * $Header: /xtel/pp/pp-beta/Chans/fax/RCS/fax_out.c,v 6.0 1991/12/18 20:07:09 jpo Rel $
  9.  *
  10.  * $Log: fax_out.c,v $
  11.  * Revision 6.0  1991/12/18  20:07:09  jpo
  12.  * Release 6.0
  13.  *
  14.  */
  15.  
  16.  
  17. #include    "util.h"
  18. #include    "retcode.h"
  19. #include     "prm.h"
  20. #include    "q.h"
  21. #include    "qmgr.h"
  22. #include    "dr.h"
  23. #include     <isode/cmd_srch.h>
  24. #include     "tb_bpt88.h"
  25. #include        "IOB-types.h"
  26. #include        "MTA-types.h"
  27. #include     <sys/stat.h>
  28. #include     <sys/time.h>
  29. #include    <varargs.h>
  30. #include    "faxgeneric.h"
  31.  
  32. extern char    *quedfldir;
  33. extern FaxCtlr    *init_faxctrlr();
  34.  
  35. static int initialise(), endfunc(), faxit(), decode_ch_out_info();
  36. static struct type_Qmgr_DeliveryStatus    *process();
  37. static void dirinit(), douser();
  38. static char *get_fax_number();
  39. static char    *this_msg;
  40. static int firstSuccessDR, firstFailureDR;
  41.  
  42. void    advise ();
  43. void    adios ();
  44. #define ps_advise(ps, f) \
  45.         advise (LLOG_EXCEPTIONS, NULLCP, "%s: %s",\
  46.                 (f), ps_error ((ps) -> ps_errno))
  47.  
  48. int         alwaysConfirm, table_verified, fax_debug;
  49. CHAN        *mychan;
  50. Q_struct    Qstruct;
  51. FaxCtlr        *faxctl = NULL;
  52.  
  53. main (argc, argv)
  54. int    argc;
  55. char    **argv;
  56. {
  57.     sys_init (argv[0]);
  58.     dirinit ();
  59.     fax_debug = 0;
  60.  
  61.     if ((faxctl = init_faxctrlr(FAX_OUTBOUND,
  62.                     argc,
  63.                     argv)) == (FaxCtlr *) NULL) {
  64.         err_abrt(RP_MECH, 
  65.              "Unable to initialise fax driver specific elements");
  66.     }
  67.  
  68. #ifdef PP_DEBUG
  69.     if (argc>1 && (strcmp(argv[1], "debug") == 0)) {
  70.         fax_debug = 1;
  71.         debug_channel_control (argc, argv, initialise, process, endfunc);
  72.     } else
  73. #endif
  74.         channel_control (argc, argv, initialise, process, endfunc);
  75. }
  76.  
  77.  
  78. /* --- routine to move to correct place in file system --- */
  79. static void dirinit()
  80. {
  81.     if (chdir (quedfldir) < 0)
  82.         err_abrt (RP_LIO,
  83.               "Unable to change directory to '%s'", quedfldir);
  84. }
  85.     
  86. /* ARGSUSED */
  87. static int endfunc (arg)
  88. struct type_Qmgr_Channel    *arg;
  89. {
  90.     if (faxctl->close != NULLIFP)
  91.         (*faxctl->close)(faxctl);
  92. }
  93.  
  94. /*   --- channel initialise routines --- */
  95.  
  96. static int initialise (arg)
  97. struct type_Qmgr_Channel    *arg;
  98. {
  99.     char    *name;
  100.  
  101.     name = qb2str (arg);
  102.  
  103.     if ((mychan = ch_nm2struct (name)) == NULLCHAN) {
  104.         PP_OPER (NULLCP,
  105.              ("Channel '%s' not known", name));
  106.         if (name != NULLCP)
  107.             free(name);
  108.         return NOTOK;
  109.     }
  110.  
  111.     if (name != NULLCP)
  112.         free(name);
  113.     
  114.      if (decode_ch_out_info(mychan -> ch_out_info, faxctl) != OK)
  115.         return NOTOK;
  116.  
  117.     if (faxctl->open != NULLIFP
  118.         &&    (*faxctl->open) (faxctl) != OK) {
  119.         PP_LOG (LLOG_EXCEPTIONS,
  120.             ("fax open failed ['%s']",
  121.              faxctl->errBuf));
  122.         return NOTOK;
  123.     }
  124.     
  125.     return OK;
  126. }
  127.  
  128. /*   --- main processing routine --- */
  129.  
  130. static struct type_Qmgr_DeliveryStatus    *process (arg)
  131. struct type_Qmgr_ProcMsg    *arg;
  132. {
  133.     struct type_Qmgr_UserList    *up;
  134.     struct prm_vars            prm;
  135.     Q_struct            *qp = &Qstruct;
  136.     ADDR                *ad_sendr = NULLADDR,
  137.                     *ad_recip = NULLADDR;
  138.     int                retval, ad_count;
  139.     
  140.     bzero ((char *) &prm, sizeof prm);
  141.     bzero ((char *) qp, sizeof *qp);
  142.     firstSuccessDR = firstFailureDR = TRUE;
  143.  
  144.     this_msg = qb2str (arg -> qid);
  145.     
  146.     PP_NOTICE (("Processing msg %s", this_msg));
  147.  
  148.     delivery_init (arg -> users);
  149.  
  150.     retval = rd_msg (this_msg, &prm, qp, &ad_sendr,
  151.              &ad_recip, &ad_count);
  152.  
  153.     if (rp_isbad (retval)) {
  154.         PP_LOG (LLOG_EXCEPTIONS, 
  155.             ("rd_msg err: %s", this_msg));
  156.         return delivery_setallstate (int_Qmgr_status_mtaFailure,
  157.                          "Can't read message");
  158.     }
  159.  
  160.     PP_NOTICE(("Fax sender: %s", ad_sendr->ad_value));
  161.  
  162.     for (up = arg -> users; up; up = up -> next)
  163.         douser (up -> RecipientId -> parm, ad_recip, this_msg);
  164.     if (rp_isbad(wr_q2dr (&Qstruct, this_msg))) {
  165.         PP_LOG (LLOG_EXCEPTIONS,
  166.                ("%s wr_q2dr failure",mychan->ch_name));
  167.         (void) delivery_resetDRs (int_Qmgr_status_mtaFailure);
  168.     }
  169.     rd_end();
  170.     prm_free(&prm);
  171.     q_free(qp);
  172.  
  173.     return deliverystate;
  174. }
  175.  
  176. /* 
  177.  * process one extension-id for this message
  178.  */
  179.  
  180. static void douser (rno, ad_recip, msgd)
  181. int    rno;
  182. ADDR    *ad_recip;
  183. char    *msgd;
  184. {
  185.     ADDR    *ap;
  186.  
  187.     PP_TRACE (("douser (%d, ad_recip, %s)", rno, msgd));
  188.  
  189.     for (ap = ad_recip; ap; ap = ap -> ad_next) {
  190.         if (rno != ap -> ad_no) 
  191.             continue;
  192.         
  193.         if (lchan_acheck (ap, mychan, 1, NULLVP) == NOTOK) {
  194.             return;
  195.         } else {
  196.              faxit (ap);
  197.             return;
  198.         }
  199.     }
  200.  
  201.     PP_LOG (LLOG_EXCEPTIONS,
  202.         ("user not recipient of %s", this_msg));
  203.  
  204.     delivery_setstate (rno, int_Qmgr_status_mtaFailure,
  205.                "user is not recipient of message");
  206. }
  207.  
  208. /* 
  209.  *    If status is not related to a failure DR, then just return status.
  210.  *    If it is a negativeDR, then check if this is the first failure. If
  211.  *    so, return negativeDR, otherwise return failure shared DR.
  212.  */
  213. static 
  214. filterQmgrStatus(status)
  215. int    status;
  216. {
  217.     int ret = status;
  218.  
  219.     if (status == int_Qmgr_status_negativeDR) {
  220.         if (!firstFailureDR)
  221.             ret = int_Qmgr_status_failureSharedDR;
  222.         firstFailureDR = FALSE;
  223.     } 
  224.  
  225.     return(ret);
  226. }
  227.  
  228. /*
  229.  * 
  230.  */
  231.  
  232. static int    faxit (ap)
  233. ADDR    *ap;
  234. {
  235.     int    retval = NOTOK;
  236.     char    file[MAXPATHLENGTH], next[MAXPATHLENGTH];
  237.     struct stat st;
  238.     int size;
  239.     struct timeval start, stop;
  240.     char    *formatdir = NULLCP;
  241.  
  242.  
  243.     size = 0;
  244.     if (qid2dir (this_msg, ap, TRUE, &formatdir) == NOTOK) {
  245.         PP_LOG (LLOG_EXCEPTIONS, ("Can't locate message %s", this_msg));
  246.         delivery_setstate (ap -> ad_no, int_Qmgr_status_mtaFailure,
  247.                    "Can't find message");
  248.         return RP_MECH;
  249.     }
  250.  
  251.     if (rp_isbad (retval = msg_rinit (formatdir))) {
  252.         PP_LOG (LLOG_EXCEPTIONS, ("msg_rinit can't init %s", formatdir));
  253.         delivery_setstate (ap -> ad_no, int_Qmgr_status_mtaFailure,
  254.                    "can't read the body");
  255.         return RP_MECH;
  256.     }
  257.  
  258. #ifdef DONE_IN_INITIALISE            
  259.     if ((*faxctl->open)(faxctl) != OK) {
  260.         PP_LOG (LLOG_EXCEPTIONS, ("%s", faxctl->errBuf));
  261.         delivery_setstate (ap -> ad_no, int_Qmgr_status_mtaFailure, 
  262.                    faxctl->errBuf);
  263.         return RP_MECH;
  264.     }
  265. #endif
  266.  
  267.     /* get phone number */
  268. {
  269.     char    *telno;
  270.     faxctl->errBuf[0] = '\0';
  271.     if (ap && (telno = get_fax_number(ap, faxctl)) != NULLCP) {
  272.         PP_NOTICE(("faxing to %s for recipient %s", telno,ap->ad_value));
  273.         strcpy(faxctl->telno, telno);
  274.         free(telno);
  275.     } else {
  276.         if (faxctl->errBuf[0] != '\0')
  277.             sprintf(faxctl->errBuf,
  278.                 "Can't determine phone number for address '%s'",
  279.                 ap -> ad_r400adr);
  280.         PP_LOG (LLOG_EXCEPTIONS, ("%s", faxctl->errBuf));
  281.         if (faxctl->abort != NULLIFP)
  282.             (*faxctl->abort)(faxctl);
  283.         delivery_setstate(ap -> ad_no, 
  284.                   filterQmgrStatus(int_Qmgr_status_negativeDR), 
  285.                   faxctl->errBuf);
  286.         set_1dr (&Qstruct, ap -> ad_no, this_msg,
  287.              DRR_UNABLE_TO_TRANSFER, -1, faxctl->errBuf);
  288.         return RP_MECH;
  289.     }
  290. }
  291.  
  292. #ifdef    SVR4                                  
  293.     (void) gettimeofday(&start);
  294. #else
  295.     (void) gettimeofday(&start, (struct timezone *)NULL);
  296. #endif
  297.     faxctl->errBuf[0] = '\0';
  298.     if (faxctl->initXmit != NULLIFP
  299.         && rp_isbad((*faxctl->initXmit)(faxctl))) {
  300.         if (faxctl->abort != NULLIFP)
  301.             (*faxctl->abort)(faxctl);
  302.         PP_LOG (LLOG_EXCEPTIONS, ("initXmit failed [%s]", 
  303.                       faxctl->errBuf));
  304.         delivery_setstate (ap -> ad_no, 
  305.                    filterQmgrStatus(faxctl->qmgrErrCode), 
  306.                    faxctl->errBuf);
  307.         if (faxctl->qmgrErrCode == int_Qmgr_status_negativeDR)
  308.             set_1dr (&Qstruct, ap -> ad_no, this_msg,
  309.                  DRR_UNABLE_TO_TRANSFER, -1, faxctl->errBuf);
  310.         return RP_MECH;
  311.     }
  312.  
  313.     if (msg_rfile (next) != RP_OK) {
  314.         if (faxctl->abort != NULLIFP)
  315.             (*faxctl->abort)(faxctl);
  316.         PP_LOG(LLOG_EXCEPTIONS, ("Empty directory %s", formatdir));
  317.         delivery_setstate (ap -> ad_no, int_Qmgr_status_mtaFailure,
  318.                    "empty directory");
  319.         return RP_MECH;
  320.     } else {
  321.         retval = OK;
  322.         do {
  323.             strcpy(file,next);
  324.             if (msg_rfile(next) != RP_OK)
  325.                 next[0] = '\0';
  326.             if (stat (file, &st) != NOTOK)
  327.                 size += st.st_size;
  328.             if (rp_isbad(fax_bodypart (faxctl, 
  329.                            file, 
  330.                            (next[0] == '\0')))) {
  331.                 PP_LOG (LLOG_EXCEPTIONS, ("fax_bodypart failed [%s]", 
  332.                               faxctl->errBuf));
  333.                 delivery_setstate (ap -> ad_no, 
  334.                            filterQmgrStatus(faxctl->qmgrErrCode), 
  335.                            faxctl->errBuf);
  336.                 if (faxctl->qmgrErrCode == int_Qmgr_status_negativeDR)
  337.                     set_1dr (&Qstruct, ap -> ad_no, 
  338.                          this_msg,
  339.                          DRR_UNABLE_TO_TRANSFER, -1, 
  340.                          faxctl->errBuf);
  341.                 if (faxctl->abort != NULLIFP)
  342.                     (*faxctl->abort)(faxctl);
  343.                 retval = NOTOK;
  344.             }
  345.         } while (retval == OK && next[0] != '\0');
  346.  
  347.         msg_rend();
  348.  
  349.         if (retval == OK) {
  350.             if ((*faxctl->termXmit)(faxctl) != OK) {
  351.                 PP_LOG(LLOG_EXCEPTIONS, ("termXmit failed [%s]", 
  352.                              faxctl->errBuf));
  353.                 delivery_setstate (ap -> ad_no, 
  354.                            filterQmgrStatus(faxctl->qmgrErrCode), 
  355.                            faxctl->errBuf);
  356.                 if (faxctl->qmgrErrCode == int_Qmgr_status_negativeDR)
  357.                     set_1dr (&Qstruct, ap -> ad_no, 
  358.                          this_msg,
  359.                          DRR_UNABLE_TO_TRANSFER, -1, 
  360.                          faxctl->errBuf);
  361.                 if (faxctl->abort != NULLIFP)
  362.                     (*faxctl->abort)(faxctl);
  363.                 retval = NOTOK;
  364.             }
  365.         }
  366.     }
  367.  
  368. #ifdef    SVR4
  369.     (void) gettimeofday (&stop);
  370. #else
  371.     (void) gettimeofday(&stop, (struct timezone *)NULL);
  372. #endif
  373.  
  374.     if (retval == OK) {
  375.         PP_NOTICE((">>> Fax: msg sent to %s in %d seconds", 
  376.                ap -> ad_value,
  377.                stop.tv_sec - start.tv_sec));
  378.  
  379.         if (alwaysConfirm == TRUE ||
  380.             ap -> ad_usrreq == AD_USR_CONFIRM ||
  381.             ap -> ad_mtarreq == AD_MTA_CONFIRM ||
  382.             ap -> ad_mtarreq == AD_MTA_AUDIT_CONFIRM) {
  383.             char    buf[BUFSIZ];
  384.             if (lexequ(faxctl->telno, "0") == 0)
  385.                 sprintf(buf, "message locally printed");
  386.             else
  387.                 sprintf(buf, "message fax'd to '%s'", 
  388.                     faxctl->telno);
  389.  
  390.             set_1dr (&Qstruct, ap -> ad_no, 
  391.                  this_msg, DRR_NO_REASON, -1, buf);
  392.  
  393.             delivery_set (ap -> ad_no, 
  394.                       (firstSuccessDR == TRUE) ?
  395.                       int_Qmgr_status_positiveDR :
  396.                       int_Qmgr_status_successSharedDR);
  397.             firstSuccessDR = FALSE;
  398.         }
  399.         else {
  400.             (void) wr_ad_status (ap, AD_STAT_DONE);
  401.             (void) wr_stat (ap, &Qstruct, this_msg, size);
  402.             delivery_set (ap -> ad_no, int_Qmgr_status_success);
  403.         }
  404.     }
  405.     return retval;
  406. }
  407.  
  408. /* 
  409.  * send a bodypart to fax machine
  410.  */
  411.  
  412. extern CMD_TABLE bptbl_body_parts88[/* x400 84 body_parts */];
  413.  
  414. static int    type_of_file(file)
  415. char    *file;
  416. {
  417.     char    *dot;
  418.     if ((dot = rindex(file, '.')) == NULLCP)
  419.         return NOTOK;
  420.     dot++;
  421.     if (lexequ(dot, rcmd_srch(BPT_G3FAX, bptbl_body_parts88)) == 0)
  422.         return BPT_G3FAX;
  423.     if (lexequ(dot, rcmd_srch(BPT_IA5, bptbl_body_parts88)) == 0)
  424.         return BPT_IA5;
  425.     return NOTOK;
  426. }
  427.  
  428. int    num_sent;
  429.  
  430. static int fax_bodypart (faxctl, file, last)
  431. FaxCtlr    *faxctl;
  432. char    *file;
  433. int    last;
  434. {
  435.     int    type;
  436.     num_sent = 0;
  437.     switch ((type = type_of_file(file))) {
  438.         case BPT_G3FAX:
  439.         if (faxctl->sendPage != NULLIFP) 
  440.             return fax_g3_bodypart (faxctl, file, last);
  441.         break;
  442.         case BPT_IA5:
  443.         if (faxctl->sendIA5File != NULLIFP)
  444.             return fax_ia5_bodypart (faxctl, file, last);
  445.         break;
  446.         default:
  447.         break;
  448.     }
  449.  
  450.     sprintf(faxctl->errBuf, "Unable to fax '%s' bodyparts",
  451.         (type == NOTOK) ? file : rcmd_srch(type, bptbl_body_parts88));
  452.     PP_LOG(LLOG_EXCEPTIONS, ("%s", faxctl->errBuf));
  453.     return RP_MECH;
  454. }
  455.  
  456. static int fax_ia5_bodypart (faxctl, file, last)
  457. FaxCtlr *faxctl;
  458. char    *file;
  459. int    last;
  460. {
  461.     int    retcode;
  462.  
  463.     PP_DBG(("hello fax_ia5_bodypart"));
  464.     if (faxctl->setIA5Params != NULLIFP
  465.         && (*faxctl->setIA5Params) (faxctl) != OK) {
  466.         PP_LOG(LLOG_EXCEPTIONS,
  467.                ("setIA5Params failed [%s]",
  468.             faxctl->errBuf));
  469.         return RP_MECH;
  470.     }
  471.     
  472.     retcode = (*faxctl->sendIA5File)(faxctl, file, last);
  473.     if (retcode == OK)
  474.         return(OK);
  475.     else 
  476.         return(RP_MECH);
  477. }
  478.  
  479. static int fax_g3_bodypart (faxctl, file, last)
  480. FaxCtlr *faxctl;
  481. char    *file;
  482. int    last;
  483. {
  484.         register PS     psin;
  485.         FILE            *fp;
  486.     struct type_IOB_G3FacsimileBodyPart    *g3fax = NULL;
  487.     int        retval = RP_MECH;
  488.  
  489.     PP_DBG (("hello fax_g3_bodypart"));
  490.  
  491.     /* read in and decode fax bodypart */
  492.  
  493.     if ((fp = fopen (file, "r")) == (FILE *)0) {
  494.         PP_SLOG(LLOG_EXCEPTIONS, file,
  495.             ("Can't open file"));
  496.         sprintf(faxctl->errBuf,
  497.             "Can't open file '%s'", file);
  498.         faxctl->qmgrErrCode = int_Qmgr_status_messageFailure;
  499.         return RP_MECH;
  500.     }
  501.  
  502.     if ((psin = ps_alloc (std_open)) == NULLPS)
  503.         {
  504.                 (void) fclose (fp);
  505.                 ps_advise (psin, "ps_alloc");
  506.         sprintf(faxctl->errBuf,
  507.             "ps_alloc failed");
  508.         faxctl->qmgrErrCode = int_Qmgr_status_messageFailure;
  509.                 return RP_MECH;
  510.         }
  511.  
  512.     if (std_setup (psin, fp) == NOTOK)
  513.         {
  514.                 ps_free (psin);
  515.                 (void) fclose (fp);
  516.                 advise (LLOG_EXCEPTIONS, NULLCP, "%s: std_setup loses", file);
  517.         sprintf(faxctl->errBuf,
  518.             "std_setup failed");
  519.         faxctl->qmgrErrCode = int_Qmgr_status_messageFailure;
  520.                 return RP_MECH;
  521.         }
  522.  
  523.     if (do_decode_fax(psin, &g3fax) == NOTOK) {
  524.                 (void) fclose (fp);
  525.         PP_LOG(LLOG_EXCEPTIONS,
  526.                ("failed to decode G3FacsimileBodyPart"));
  527.                 ps_done(psin, "ps2pe");
  528.         sprintf(faxctl->errBuf,
  529.             "unable to decode fax bodypart");
  530.         faxctl->qmgrErrCode = int_Qmgr_status_messageFailure;
  531.                 return RP_MECH;
  532.         }
  533.  
  534.         (void) fclose (fp);
  535.  
  536.  
  537.     if (g3fax->parameters
  538.         && faxctl->setG3Params != NULLIFP
  539.         && (*faxctl->setG3Params)(faxctl, g3fax->parameters) != OK) {
  540.         PP_LOG(LLOG_EXCEPTIONS,
  541.                ("setG3Params failed [%s]", faxctl->errBuf));
  542.         return RP_MECH;
  543.     }
  544.             
  545.     if (fax_bitstrings (faxctl, g3fax, last) == OK)
  546.         retval = OK;
  547. /*    if (g3fax != NULL)
  548.         free_IOB_G3FacsimileBodyPart(g3fax);*/
  549.         return retval;
  550. }
  551.  
  552. /* 
  553.  * send each page of g3fax to fax machine 
  554.  */
  555.  
  556. static int fax_bitstrings (faxctl, g3fax, last)
  557. FaxCtlr    *faxctl;
  558. struct type_IOB_G3FacsimileBodyPart    *g3fax;
  559. int last;
  560. {
  561.     struct type_IOB_G3FacsimileData    *ix;
  562.     int retval;
  563.     
  564.     for (ix = g3fax -> data; ix != NULL; ix = ix -> next) {
  565.         int        len;
  566.         char    *str;
  567.  
  568.         if ((str = bitstr2strb (ix -> element_IOB_0, &len)) == NULLCP) {
  569.             PP_LOG(LLOG_EXCEPTIONS, ("empty page"));
  570.             return NOTOK;
  571.         }
  572.         len = (len + BITSPERBYTE -1)/BITSPERBYTE;
  573.  
  574.         retval = faxctl->sendPage(faxctl, str, len, 
  575.                       (last && ix -> next == NULL));
  576.         free (str);
  577.         if (retval != OK)
  578.             return retval;
  579.     }
  580.     return  OK;
  581. }
  582.  
  583. /*
  584.  * parse info field
  585.  */
  586.  
  587. static int decode_ch_out_info(info, faxctl)
  588. char    *info;
  589. FaxCtlr    *faxctl;
  590. {
  591.   char    *info_copy;
  592.   int    margc,i;
  593.   char    *margv[100];
  594.  
  595.   if (info == NULLCP) 
  596.     return OK;
  597.  
  598.   info_copy = strdup(info);
  599.   margc = sstr2arg(info_copy, 100, margv, ",=");
  600.   
  601.   alwaysConfirm = FALSE;
  602.  
  603.   for (i = 0; i < margc; i++) {
  604.       /* PP specific args */
  605.       if (lexequ(margv[i], "confirm") == 0) {
  606.           i++;
  607.           if (lexequ(margv[i], "always") == 0)
  608.               alwaysConfirm = TRUE;
  609.           else if (lexequ(margv[i], "never") == 0)
  610.               alwaysConfirm = FALSE;
  611.       } else if (faxctl->arg_parse != NULLIFP) {
  612.           /* pass to driver specific parser */
  613.           if ((*faxctl->arg_parse) (faxctl, 
  614.                         margv[i], 
  615.                         margv[i+1]) == OK)
  616.               i++;
  617.           else {
  618.               PP_LOG(LLOG_EXCEPTIONS,
  619.                  ("%s", faxctl->errBuf));
  620.               free(info_copy);
  621.               return NOTOK;
  622.           }
  623.       } else {
  624.           PP_LOG(LLOG_EXCEPTIONS,
  625.              ("No arg_parse routine registered, unrecognised ch_info element '%s'",
  626.               margv[i]));
  627.           free(info_copy);
  628.           return NOTOK;
  629.       }
  630.   }
  631.   free(info_copy);
  632.   return OK;
  633. }
  634.  
  635. /*
  636.  *
  637.  * address to telephone number mapping via table lookup
  638.  */
  639.  
  640. static void tblentry2num(buf, ptelno, porg)
  641. char    *buf;
  642. char    **ptelno;
  643. char    **porg;
  644. {
  645.     /* parse as number,rest */
  646.     char    *telno = NULLCP, *org = NULLCP, *ix;
  647.  
  648.     if ((ix = index(buf, ',')) == NULLCP) {
  649.         compress(buf,buf);
  650.         telno = strdup(buf);
  651.     } else {
  652.         *ix++ = '\0';
  653.         compress(buf, buf);
  654.         telno = strdup(buf);
  655.         /* for now rest is company */
  656.         if (*ix != '\0') 
  657.             org = strdup(ix);
  658.     }
  659.  
  660.     if (ptelno != NULL) 
  661.         *ptelno = telno;
  662.     else if (telno != NULLCP)
  663.         free(telno);
  664.           
  665.     if (porg != NULL)
  666.         *porg = org;
  667.     else if (org != NULLCP)
  668.         free(org);
  669. }
  670.  
  671. static char *get_fax_number(adr, faxctl)
  672. ADDR    *adr;
  673. FaxCtlr    *faxctl;
  674. {
  675.     OR_ptr    or, or2;
  676.     char    *telno = NULLCP, buffer[BUFSIZ];
  677.     int    using_outmta = FALSE;
  678.     table_verified = FALSE;
  679.  
  680.     if (adr->ad_r400adr == NULLCP
  681.         || adr->ad_r400adr[0] != '/')
  682.         return NULLCP;
  683.  
  684.     if ((or = or_std2or(adr->ad_r400adr)) == NULLOR) {
  685.         sprintf(faxctl->errBuf,
  686.             "Unable to parse X.400 address '%s'",
  687.             adr->ad_r400adr);
  688.         PP_LOG(LLOG_EXCEPTIONS,
  689.                ("%s",faxctl->errBuf));
  690.         return NULLCP;
  691.     }
  692.     or2 = or;
  693.     while ((or2 = or_locate (or2, OR_DD)) != NULLOR) {
  694.         if (cmd_srch(or2->or_ddname, 
  695.                  ortbl_ddvalid) == OR_DDVALID_FAX) {
  696.             telno = strdup (or2->or_value);
  697.             break;
  698.         } else if (or2 -> or_next != NULLOR)
  699.             or2 = or2 -> or_next;
  700.         else
  701.             break;
  702.         
  703.     }
  704.      
  705.     /* use outmta */
  706.     if (telno == NULLCP 
  707.         && adr -> ad_outchan != NULLIST_RCHAN) {
  708.         using_outmta = TRUE;
  709.         telno = strdup(adr -> ad_outchan -> li_mta);
  710.     } 
  711.     if (telno != NULLCP
  712.         && mychan != NULLCHAN
  713.         && mychan -> ch_table != NULLTBL
  714.         && tb_k2val (mychan -> ch_table, telno, buffer, TRUE) != NOTOK) {
  715.         table_verified = TRUE;
  716.         PP_NOTICE(("fax key '%s' verfied in table '%s'",
  717.                telno, mychan -> ch_table -> tb_name));
  718.         free (telno);
  719.         tblentry2num(buffer, &telno, (char **) NULL);
  720.     } else if (using_outmta == TRUE) {
  721.         sprintf(faxctl->errBuf,
  722.             "Unable to obtain remote fax info for address '%s'",
  723.             adr->ad_r400adr);
  724.         PP_LOG(LLOG_EXCEPTIONS,
  725.                ("%s", faxctl->errBuf));
  726.         if (telno)
  727.             free(telno);
  728.         if (or)
  729.             or_free(or);
  730.         return NULLCP;
  731.     }
  732.     if (or)
  733.         or_free(or);
  734.     return telno;
  735. }
  736.  
  737. /* 
  738.  * decode from PE to C struct
  739.  */
  740.  
  741. extern PE    ps2pe_aux ();
  742.  
  743. static int do_decode_fax (psin, pfax)
  744. register PS    psin;
  745. struct type_IOB_G3FacsimileBodyPart    **pfax;
  746. {
  747.     struct type_IOB_G3FacsimileData        *new, *tail = NULL;
  748.     int                    pages;
  749.     register PE                 pe = NULLPE;
  750.     
  751.     /* get first chunk */
  752.     if ((pe = ps2pe_aux (psin, 1, 0)) == NULLPE) {
  753.         ps_done (psin, "ps2pe_aux");
  754.         return NOTOK;
  755.     }
  756.     
  757.     if ((PE_ID(pe -> pe_class, pe -> pe_id) !=  
  758.          PE_ID(PE_CLASS_UNIV, PE_CONS_SEQ))
  759.         && (PE_ID(pe -> pe_class, pe -> pe_id) !=
  760.         PE_ID(PE_CLASS_CONT, (PElementID) 0x03))) {
  761.         PP_LOG(LLOG_EXCEPTIONS,
  762.                ("Unexpected pe in G3FacsimileBodyPart: expected sequence"));
  763.         return NOTOK;
  764.     }
  765.     
  766.     pe_free (pe);
  767.  
  768.     *pfax = (struct type_IOB_G3FacsimileBodyPart *) calloc (1,
  769.                                    sizeof (struct type_IOB_G3FacsimileBodyPart));
  770.     
  771.     /* get and decode parameters */
  772.     if ((pe = ps2pe (psin)) == NULLPE) { /* EOF or error? */
  773.         ps_done (psin, "ps2pe");
  774.         return NOTOK;
  775.         }
  776.         PY_pepy[0] = 0;
  777.  
  778.     if (decode_IOB_G3FacsimileParameters(pe, 1, 
  779.                         NULLIP, NULLVP, 
  780.                         &((*pfax) -> parameters)) == NOTOK) {
  781.         PP_LOG(LLOG_EXCEPTIONS,
  782.                ("decode_IOB_G3FacsimileParameters failure [%s]",
  783.             PY_pepy));
  784.         pe_done(pe, "Parse failure IOB_G3FacsimileParameters");
  785.         return NOTOK;
  786.     }
  787.     
  788.     if (PY_pepy[0] != 0)
  789.         PP_LOG(LLOG_EXCEPTIONS,
  790.                ("parse_IOB_G3FacsimileParameters non fatal failure [%s]",
  791.                         PY_pepy));
  792.  
  793.     pe_free (pe);
  794.  
  795.     /* get next chunk */
  796.     if ((pe = ps2pe_aux (psin, 1, 0)) == NULLPE) {
  797.         ps_done (psin, "ps2pe_aux");
  798.         return NOTOK;
  799.     }
  800.     
  801.     if (PE_ID(pe -> pe_class, pe -> pe_id) != 
  802.         PE_ID(PE_CLASS_UNIV, PE_CONS_SEQ)) {
  803.         PP_LOG(LLOG_EXCEPTIONS,
  804.                ("Unexpected pe in G3FacsimileBodyPart: expected sequence"));
  805.         return NOTOK;
  806.     }
  807.  
  808.     pe_free (pe);
  809.     
  810.     pages = 0;
  811.     while ((pe = ps2pe (psin)) != NULLPE) {
  812.         switch (PE_ID(pe -> pe_class, pe -> pe_id)) {
  813.             case PE_ID (PE_CLASS_UNIV, PE_PRIM_BITS):
  814.             break;
  815.             case PE_ID (PE_CLASS_UNIV, PE_UNIV_EOC) :
  816.             pe_free(pe);
  817.             continue;
  818.             default:
  819.             PP_LOG(LLOG_EXCEPTIONS,
  820.                    ("Unexpected pe in G3FacsimileBodyPart: expected bitstring"));
  821.             return NOTOK;
  822.         }
  823.         new = (struct type_IOB_G3FacsimileData *) (calloc (1,
  824.                                   sizeof(struct type_IOB_G3FacsimileData)));
  825.         new -> element_IOB_0 = prim2bit(pe);
  826.         if ( (*pfax) -> data == NULL)
  827.             (*pfax) -> data = tail = new;
  828.         else {
  829.             tail -> next = new;
  830.             tail = tail -> next;
  831.         }
  832.         pages++;
  833.     }
  834.     
  835.     if ((*pfax) -> parameters -> optionals == opt_IOB_G3FacsimileParameters_number__of__pages
  836.         && (*pfax) -> parameters -> number__of__pages != pages) {
  837.         PP_LOG(LLOG_EXCEPTIONS, 
  838.                ("Incorrect number of pages in G3FacsimileBodyPart: expected %d, got %d",
  839.             (*pfax) -> parameters -> number__of__pages, pages));
  840.         return NOTOK;
  841.     }
  842.     return OK;
  843. }
  844.  
  845. /* 
  846.  * various isode-like routines
  847.  */
  848.  
  849. /* pe_done: utility routine to do the right thing for pe errors */
  850. int             pe_done (pe, msg)
  851. PE              pe;
  852. char            *msg;
  853. {
  854.         if (pe->pe_errno)
  855.         {
  856.                 PP_OPER(NULLCP,
  857.                         ("%s: [%s] %s",msg,PY_pepy,pe_error(pe->pe_errno)));
  858.                 pe_free (pe);
  859.                 return NOTOK;
  860.         }
  861.         else
  862.         {
  863.                 pe_free (pe);
  864.                 return OK;
  865.         }
  866. }
  867.  
  868. /* ps_done: like pe_done */
  869. int             ps_done (ps, msg)
  870. PS              ps;
  871. char           *msg;
  872. {
  873.         ps_advise (ps, msg);
  874.         ps_free (ps);
  875.         return NOTOK;
  876. }
  877.  
  878. #ifndef lint
  879. void    adios (va_alist)
  880. va_dcl
  881. {
  882.         va_list ap;
  883.  
  884.         va_start (ap);
  885.  
  886.         _ll_log (pp_log_norm, LLOG_FATAL, ap);
  887.  
  888.         va_end (ap);
  889.  
  890.         _exit (1);
  891. }
  892. #else
  893. /* VARARGS2 */
  894.  
  895. void    adios (what, fmt)
  896. char   *what,
  897.        *fmt;
  898. {
  899.         adios (what, fmt);
  900. }
  901. #endif
  902.  
  903.  
  904. #ifndef lint
  905. void    advise (va_alist)
  906. va_dcl
  907. {
  908.         int     code;
  909.         va_list ap;
  910.  
  911.         va_start (ap);
  912.  
  913.         code = va_arg (ap, int);
  914.  
  915.         _ll_log (pp_log_norm, code, ap);
  916.  
  917.         va_end (ap);
  918. }
  919. #else
  920. /* VARARGS3 */
  921.  
  922. void    advise (code, what, fmt)
  923. char   *what,
  924.        *fmt;
  925. int     code;
  926. {
  927.         advise (code, what, fmt);
  928. }
  929. #endif
  930.